/**
 * Copyright (c) 2022 Presto Labs Pte. Ltd.
 * Author: Ju
 */
#pragma once

#include <cstdint>
#include <memory>
#include <string>
#include <unordered_map>

#include <boost/asio/io_service.hpp>

#include "coin2/base/influxdb/influxdb_builder.h"
#include "coin2/base/influxdb/influxdb_client.h"
#include "coin2/base/request/i_session_pool.h"
#include "coin2/base/scheduler.h"
#include "coin2/exchange/base/order/stats/system_info.h"

namespace coin2::exchange::base::order {
namespace influxdb = coin2::base::influxdb;
using RttInfo = coin2::base::request::RttInfo;
using RequestStatus = coin2::base::request::RequestStatus;
struct StatsInfo {
  StatsInfo() : order_reject_num(0), order_accept_num(0), cancel_reject_num(0) {}
  void Reset() {
    order_reject_num = 0;
    order_accept_num = 0;
    cancel_reject_num = 0;
  }
  StatsInfo(const StatsInfo& info)
      : order_reject_num(info.order_reject_num),
        order_accept_num(info.order_accept_num),
        cancel_reject_num(info.cancel_reject_num) {}
  StatsInfo& operator=(StatsInfo&& info) {
    order_reject_num = info.order_reject_num;
    order_accept_num = info.order_accept_num;
    cancel_reject_num = info.cancel_reject_num;
    info.Reset();
    return *this;
  }
  StatsInfo& operator=(const StatsInfo& info) {
    if (this != &info) {
      order_reject_num = info.order_reject_num;
      order_accept_num = info.order_accept_num;
      cancel_reject_num = info.cancel_reject_num;
    }

    return *this;
  }

  uint32_t order_reject_num;
  uint32_t order_accept_num;
  uint32_t cancel_reject_num;
};

struct Info {
  RequestStatus req_info;
  StatsInfo stats_info;
  RttInfo rtt_info;
  int ws_reset_num;
};

class StatsManager {
 public:
  class Callback {
   public:
    virtual ~Callback() = default;
    virtual void OnGenricReport() = 0;
  };
  StatsManager(
      boost::asio::io_context* ioc,
      boost::asio::io_context* main_ioc,
      Callback* callback,
      const std::string& strategy_name);
  ~StatsManager();

  void Run();
  void
  RegisterBuilder(const std::string& sys_name, const std::string& mea, const std::string& owner);

  void RegisterEndPointBuilder(
      const std::string& mea,
      const std::string& method,
      const std::string& target);
  void RegisterCallback(Callback* callback);
  void GenericReport(const std::string& system_name, const std::string& mea, Info info);

 private:
  void DoReport();

  void SysInfoReport();

 private:
  boost::asio::io_context* ioc_;
  boost::asio::io_context* main_ioc_;
  Callback* callback_;
  std::shared_ptr<Scheduler> timer_;
  std::unique_ptr<influxdb::InfluxdbClient> client_;
  std::unordered_map<std::string, influxdb::Builder> builders_;
  influxdb::Builder sys_info_builder_;
  StatsInfo info_;

  SystemInfo sys_info_;

  std::string strategy_name_;
};

inline void StatsManager::RegisterCallback(Callback* callback) { callback_ = callback; }

}  // namespace coin2::exchange::base::order
